;
;	****************************
;
;		Z-80 TRACER
;
;	****************************
;
; THIS PROGRAM USES THE TRACER
; PROGRAM WRITTEN BY ARTHUR W. CLINE
; AND PUBLISHED IN DR. DOBB'S JOURNAL
; VOLUME 3,ISSUE 3,MAR 1978
;
; VERSION 1.1 25 OCTOBER 81
;
; THIS IS A STAND ALONE TRACER FOR
; 8080/Z80 PROGRAMS TO BE EXECUTED
; ON A Z80 COMPUTER. AS WRITTEN IT
; DUMPS THE CONTENTS OF THE REGISTERS
; PRIOR TO EXECUTING AN OP-CODE. IT
; THEN CALCULATES THE NEXT OP-CODE
; LOCATION AND PLACES A RESTART THERE.
; THE TARGET PROGRAM AND TRACER MUST
; BE IN R/W MEMORY SINCE THEY ARE
; MODIFIED DURING EXECUTION.
;
; TRANSLATED TO TDL MNEMONICS AND
; MADE INTO A STAND ALONE PROGRAM
;                BY
;           CHARLES THOMAS
;           416 GREENWOOD DR.
;           CLINTON, TN.
;           37716
;
.RADIX	16
.PABS
.XSYM
;
;===========================
; HARDWARE DEPENDANT EQUATES
;===========================
;
;CONSOLE OUTPUT ROUTINE.
;DATA IS PASSED IN THE 'A' REG
;THE 'HL','DE',AND 'BC' REGISTERS
;MUST BE PRESERVED BY THE CALLED
;ROUTINE.
;
COUT	= 0D006H
;
;KEYBOARD STATUS PORT
;
CSTAT	= 0D5H
;
;KEYBOARD DATA PORT
;
CDATA	= 0D4H
;
;MASK FOR READY BIT FOR
;KEYBOARD STATUS.
;THE PROGRAM EXPECTS THE RDY BIT
;TO BE HIGH WHEN DATA IS AVAILABLE.
;IF YOUR RDY BIT IS TRUE LOW YOU MUST
;CHANGE THE 'CTEST' SUBROUTINE.
;
RDYMSK	= 80H		;BIT 8
;
.LOC	8000H
;
;SET UP RESTART VECTORS AND
;INSTALL RESTART IN TARGET
;PROGRAM.
;
INIT:	LXI	SP,STACK + 20
	LXI	H,MSG1	;TRACE @
	CALL	MSGOUT
	CALL	ADDIN	;GET ADDRESS
	MOV	A,M	;GET B1
	STA	B1
	MVI	M,0F7	;PUT IN RST6
	INX	H	;GET B2
	MOV	A,M
	STA	B2
	LXI	H,PREDMP
	SHLD	31	;RESTART VECTOR
	MVI	A,0C3
	STA	30	;PUT IN JUMP
	LXI	H,MSG2
	CALL	MSGOUT	;START TARGET @
	CALL	ADDIN	;GET ADDRESS
	PCHL		;GO RUN IT
;
; SUBROUTINE VECTORED TO BY RESTART.
; IT SAVES THE STACK POINTER AND THE
; REGISTER CONTENTS.
;
PREDMP: SSPD	ST1+1	;SAVE FOR TRACER
	SSPD	RET2+1	;SAVE FOR TARGET
	SHLD	RET1+1	;SAVE HL
	POP	H	;GET RETURN ADDR
	DCX	H	;ADJUST IT
        LXI	SP,WSTAK 
	PUSH	H	;PUT RETURN ON IT
RET1:	LXI	H,0	;RESTORE HL
	PUSH	PSW	;SAVE REGS
	PUSH	B
	PUSH	D
	PUSH	H
	PUSH	X
	LHLD	RET2+1
	PUSH	H	;SAVE SP
	EXAF
	PUSH	PSW
	EXAF
	EXX
	PUSH	B
	PUSH	D
	PUSH	H
	EXX
	PUSH	Y
	JMP	DUMP	;USER DISPLAY ROUTINE
;
; SUBROUTINE TO RESTORE REGISTERS
; AND REENTER TARGET PROGRAM.
;
REENT:	LXI	SP,SAVHL
	POP	H	;RESTORE REGS
	POP	D
	POP	B
	POP	PSW
RET2:	LXI	SP,0	;RESTORE TARGET STACK
	RET		;BACK TO TARGET PRGM
;
;=====================
; MAIN TRACER PROGRAM.
;=====================
;
;TRACER RESTORES OPCODE
;AT THE BREAKPOINT,CALCULATES
;THE NEXT OP-CODE TO BE EXECUTED
;THEN RESTORES THE REGISTERS AND
;REENTERS THE TARGET PROGRAM.
;
START:  MVI	D,0F7	;RESTART OP-CODE
	LHLD	B2	;DISPLACED OP-CODE
ST1:	LXI	SP,0	;TARGET SP
	MOV	A,H	;FIRST BYTE  (B1)
	MOV	E,A	; E = B1
	CPI	76	;HALT INST?
	JZ	AHALT	;EXIT ===>
	CPI	0FD	;INDEX TYPE?
	JZ	IX
	CPI	0DD
	JZ	IX
	CPI	0CB
	JZ	TWOBT
	CPI	0E9
	JZ	PCHL
	CPI	0ED
	JZ	EDCODE
;
; TEST FOR RETURN TYPE INSTR.
;
	LXI	B,0A
	LXI	H,ONE
	CCIR
	XRA	A
	CMP	C
	JNZ	RETTST
;
; TEST FOR THREE BYTE LOADS
;
	MOV	A,E
	LXI	B,9
	CCIR
	XRA	A
	CMP	C
	JNZ	THRBT
;
; TEST FOR TWO BYTE LOADS
;
	MOV	A,E
	LXI	B,13
	CCIR
	XRA	A
	CMP	C
	JNZ	TWOBT
;
;TEST FOR THREE BYTE CALLS AND JMPS
;
	MOV	A,E
	LXI	B,13
	CCIR
	XRA	A
	CMP	C
	JNZ	CALLTST
;
; TEST FOR RESTARTS
;
	MOV	A,E
	LXI	B,7
	CCIR
	XRA	A
	CMP	C
	JNZ	RST
;
; TEST FOR RELATIVE JUMPS
;
	MOV	A,E
	LXI	B,7
	CCIR
	XRA	A
	CMP	C
	JNZ	JRTST
	JMPR	ONEBT
;
; TEST FOR DD/FD/ED __ XX XX INSTR.
;
EDCODE: MOV	A,L	;A = B2
	LXI	B,0C
	LXI	H,DDFD4
	CCIR
	XRA	A
	CMP	C
	JRNZ	FRBT
	JMPR	TWOBT
;
;TEST FOR DD/FD __ XX INSTR
;
IX:	MOV	A,L	;A = B2
	LXI	B,19
	LXI	H,DDFD3
	CCIR
	XRA	A
	CMP	C
	JRNZ	THRBT
;
; TEST FOR DD/FD __ INSTR
;
	MOV	A,E
	LXI	B,0C
	CCIR
	XRA	A
	CMP	C
	JRNZ	TWOBT
;
;  FOLLOWING ROUTINES:
;     1) RESTORE DISPLACED OP-CODE
;     2) EXIT WITH HL ->NXT OP-CODE
; ENTER WITH RESTART ADDR+1 ON STACK
; AND E REG =DISPLACED BYTE (B1).
;
FRBT:	POP	H	;LOC OF RESTART + 1
	DCX	H	;PT TO RESTART
	PUSH	H	;SET UP RETURN
	MOV	A,E	;RESTORE DISPLACED CODE
	MOV	M,A
	INX	H	;HL -> NEXT OP-CODE
	INX	H
	INX	H
	INX	H
	JMPR	RT1
;
THRBT:	POP	H
	DCX	H
	PUSH	H
	MOV	A,E
	MOV	M,A
	INX	H
	JMPR	TW1
;
TWOBT:	POP	H
	DCX	H
	PUSH	H
	MOV	A,E
	MOV	M,A
TW1:	INX	H
	INX	H
	JMPR	RT1
;
ONEBT:	POP	H
	DCX	H
	PUSH	H
	MOV	A,E
	MOV	M,A
	INX	H
	JMPR	RT1
;
CALL:	POP	H
	DCX	H
	PUSH	H
	MOV	A,E
	MOV	M,A	;RESTORE OP-CODE
	INX	H	;GET CALL ADDR.
	MOV	E,M
	INX	H
	MOV	D,M
	XCHG		;HL->NXT OP-CODE
	MOV	A,M
	MVI	M,0F7	;INSTALL RST
	JMPR	RT2
;
JR:	POP	H
	DCX	H
	PUSH	H
	MOV	A,E
	MOV	M,A	;RESTORE OP-CODE
	INX	H
	MOV	A,M	;RELATIVE OFFSET
	CMP	B
	JM	JR1	;J IF NEG OFFSET
	INX	H
	ADD	L	;CALC NXT ADDR.
	JMPR	JR2
;
JR1:	CMP	L
	MOV	B,A
	MOV	A,L
	SUB	B	;CALC NXT ADDR.
JR2:	MOV	L,A	;HL->NXT OP-CODE
	JMPR	RT1
;
;ON A RESTART THE PROGRAM EXPECTS A
;JUMP INSTRUCTION. THE ROUTINE GETS
;THE ADDRESS OF THE JUMP AND PUTS IT
;IN THE HL REG.
;
RST:	POP	H
	DCX	H
	PUSH	H
	MOV	A,E	;RESTORE OP-CODE
	MOV	M,A
	XRI	0C7	;WHICH RESTART?
	INR	A	;RST ADDR + 1
	MOV	L,A
	MVI	H,0	;HL = RESTART + 1
	SPHL
	POP	H	;HL->NXT OP-CODE
	JMPR	RT1
;
PCHL:	POP	H
	DCX	H
	PUSH	H
	MOV	A,E
	MOV	M,A	;RESTORE OP-CODE
	LHLD	SAVHL	;GET HL
	JMPR	RT1
;
RET:	POP	H
	DCX	H
	PUSH	H
	MOV	A,E
	MOV	M,A	;RESTORE OP-CODE
	POP	H	;GET PAST RENTRY PT.
	POP	H	;HL->RETURN ON STACK
RT1:	MOV	A,M	;NXT OP-CODE
	MOV	M,D	;PUT IN RESTART
RT2:	STA	B1	;SAVE OP-CODE
	JMPR	END	;GO EXIT
;
; TEST CONDITIONAL RELATIVE JUMPS
; TO DETERMINE NEXT OP-CODE TO BE
; EXECUTED.
; ROUTINE INSTALLS THE OP-CODE IN
; ITSELF AND RESTORES PSW. IT THEN
; EXECUTES THE OPCODE TO DETERMINE
; THE CONDITIONAL RESULT.
;
JRTST:	MOV	A,E
	LXI	SP,SAVPSW
	STA	JRT1	;PUT OP-CODE IN!
	POP	PSW	;TARGET PSW
JRT1:	JMPR	JT1	;TEST DONE HERE!
	LSPD	ST1+1	;<- IF NO JMP
	JMPR	TWOBT
;
JT1:	LSPD	ST1+1	;<- IF JMP
	JMPR	JR	;CALC REL JMP
;
; CONDITIONAL CALL TEST
; PROGRAM STORES CONDITIONAL CALL
; IN ITSELF AND TESTS THE RESULT.
;
CALLTST:MOV	A,E
	LXI	SP,SAVPSW
	STA	CALL1	;PUT IN OPCODE
	POP	PSW	;TARGET PSW
	LXI	SP,0FFFF;OUT OF THE WAY
CALL1:	CALL	CALL3	;TEST HERE!
CALL2:	LSPD	ST1+1	;<-IF NO CALL
	JMP	THRBT
;
CALL3:	LSPD	ST1+1	;<-IF CALL
	JMP	CALL
;
; CONDITIONAL RETURN TEST
; INSTALLS CONDITIONAL RETURN
; THEN EXECUTES IT TO OBSERVE
; THE RESULT.
;
RETTST: MOV	A,E	;B1
	LXI	SP,SAVPSW
	STA	RE1	;PUT IN OPCODE
	POP	PSW	;TARGET PSW
	LXI	SP,DSPL	;SP -> RE2
RE1:	RET		;TEST HERE!
	LSPD	ST1+1	;<-IF NO RETURN
	JMP	ONEBT
;
RE2:	LSPD	ST1+1	;<-IF RETURN
	JMP	RET
;
DSPL:	.WORD	RE2	;RET ADDR FOR TEST
;
END:	INX	H	;SECOND BYTE OF OP-CODE
	MOV	A,M
	STA	B2	;SAVE IT
	JMP	REENT	;GO REENTER TARGET PRGM
;
;======================
; REGISTER DUMP ROUTINE
;======================
;ROUTINE TO DISPLAY CONTENTS OF
;REGISTERS TO THE DISPLAY DEVICE
;
DUMP:	LXI	SP,STACK
	LXI	H,SAVRST+1
	LXI	D,RLABEL
	MVI	C,0DH	;FIELDS TO DISP.
..A:	CALL	REGOUT	;PRINT A FIELD
	DCR	C
	JRNZ	..A	;LOOP TILL DONE
	CALL	CTEST	;CK KEYBD
	JZ	START	;Z=NO KEY
	CPI	1BH	;PAUSE CHAR?
	JNZ	START	;NZ=NO
	LXI	H,PROMPT
	CALL	MSGOUT
..B:	CALL	CTEST
	JRZ	..B	;Z=NOT YET
	CPI	1BH
	JZ	START
	ANI	0DF	;EITHER 'X'
	CPI	'X'
	JZ	RESTORE	;COMMAND MODE
	JMPR	..B
;
;OUTPUT REGISTER LABEL AND
;CONTENTS.
;
REGOUT:	XCHG
	CALL	MSGOUT	;PRNT LABEL
	XCHG
	CALL	HXOUT	;SEND A BYTE
	DCX	H
	CALL	HXOUT
	DCX	H
	RET
;
MSGOUT:	MOV	B,M	;MSG LENGTH
..A:	INX	H	;GET CHAR
	MOV	A,M
	CALL	COUT	;PRINT IT
	DCR	B
	JRNZ	..A	;NZ=NOT DONE
	INX	H
	RET
;
;OUTPUT (HL) IN ASCII
;
HXOUT:	MOV	A,M
	RAR		;LOWER NIBBLE
	RAR
	RAR
	RAR
	CALL	BINAS	;CONVERT
	MOV	A,M
BINAS:	ANI	0FH
	ADI	30H
	CPI	3AH
	JRC	..A
	ADI	07H
..A:	CALL	COUT
	RET
;
;KEYBOARD INPUT ROUTINE.
;RETURNS WITH:
;   Z=1  NO KEY PUSHED
;   Z=0  KEY PUSHED (DATA IN 'A' REG)
;
CTEST:	IN	CSTAT	;KEY PUSHED?
	ANI	RDYMSK	;CK RDY BIT
	RZ		;Z=NO KEY
	IN	CDATA	;GET DATA
	ANI	7F	;MASK PARITY
	RET
;
;INPUT A HEX ADDRESS.
;RETURNS WITH ADDRESS
;IN HL REG.
;
ADDIN:	LXI	H,0	;START WITH 0
..A:	CALL	CTEST	;KEY?
	JRZ	..A
	CPI	0D	;DONE?
	RZ		;Z=YES
	MOV	B,A	;SAVE CHAR
	CPI	61	;LOWER CASE?
	JRC	..B	;C = NO
	SUI	20	;REMOVE BIAS
..B:	SUI	'0'	;ASCII BIAS
	JRC	..A	;C=NOT HEX 
	CPI	17
	JRNC	..A	;NC= NOT HEX 
	CPI	10
	JRZ	..A	;Z= NOT HEX
	JRC	..C	;C= < 'A'
	SUI	7	;MORE BIAS
..C:	DAD	H	;SHIFT OVER
	DAD	H
	DAD	H
	DAD	H
	ORA	L	;PUT IN CHAR
	MOV	L,A
	MOV	A,B	;GET ORIGINAL
	CALL	COUT	;ECHO IT
	JMPR	..A	;MORE DIGITS
;
;FLAG HALT AND GO TO COMMAND MODE
;
AHALT:	LXI	H,HLTMSG
	CALL	MSGOUT	;PRINT IT
;
;RESTORE TARGET PROGRAM
;
RESTORE:LDA	B1	;DISPLACED OP-CODE
	LHLD	SAVRST	;RESTART LOC.
	MOV	M,A	;FIX IT
	JMP	INIT	;TO COMMAND MODE
;
;===========================
; LOOK UP TABLES FOR VARIOUS
; OP-CODES.
;===========================
;
TABLE:
ONE:	.BYTE	0C0,0C8,0D0,0D8
	.BYTE	0E0,0E8,0F0,0F8
	.BYTE	0C9,0
;
THRLDS: .BYTE	01,11,21,31
	.BYTE	22,2A,32,3A
	.BYTE	0
;
TBYTE:	.BYTE	06,0E,16,1E
	.BYTE	26,2E,36,3E
	.BYTE	0D3,0DB,0C6,0CE
	.BYTE	0D6,0DE,0E6,0EE
	.BYTE	0F6,0FE,0
;
JMPCAL:	.BYTE	0C2,0CA,0D2,0DA
	.BYTE	0E2,0EA,0F2,0FA
	.BYTE	0C3,0C4,0CC,0D4
	.BYTE	0DC,0E4,0EC,0F4
	.BYTE	0FC,0CD,0
;
RSTS:	.BYTE	0CF,0D7,0DF,0E7
	.BYTE	0EF,0F7,0
;
JRS:	.BYTE	10,18,20,28
	.BYTE	30,38,0
;
DDFD3:	.BYTE	34,35,70,71
	.BYTE	72,73,74,75
	.BYTE	77,46,4E,56
	.BYTE	5E,66,6E,7E
	.BYTE	86,8E,96,9E
	.BYTE	0A6,0AE,0B6,0BE
	.BYTE	0
;
DDFD2:	.BYTE	09,19,23,29
	.BYTE	2B,39,0E1,0E3
	.BYTE	0E5,0E9,0F9,0
;
DDFD4:	.BYTE	21,22,2A,36
	.BYTE	43,4B,53,5B
	.BYTE	73,7B,0CB,0
;
;LABELS FOR REGISTER DISPLAY
;
RLABEL:	.ASCII	[5][0D][0A]'PC='
	.ASCII	[4]' AF='
	.ASCII	[4]' BC='
	.ASCII	[4]' DE='
	.ASCII	[4]' HL='
	.ASCII	[4]' IX='
	.ASCII	[4]' SP='
	.ASCII	[0D][0D][0A]"        AF'"
	.ASCII	[4]" BC'"
	.ASCII	[4]" DE'"
	.ASCII	[4]" HL'"
	.ASCII	[4]" IY="
	.ASCII	[4]" B1="
MSG1:	.ASCII	[13][0D][0A]"START TRACE AT-> "
MSG2:	.ASCII	[13][0D][0A]"START TARGET AT> "
PROMPT:	.ASCII	[0A] [0D][0A]" TRACE >"
HLTMSG:	.ASCII	[0C] [0D][0A]"HALTED !!!"
;
;===============================
;TEMPORARY STORAGE FOR DISPLACED
;BYTES FROM TARGET PROGRAM.
;===============================
;
B2:	.BYTE	0	;FIRST BYTE
B1:	.BYTE	0	;SECOND BYTE
;
;====================================
;STORAGE FOR TARGET PROGRAM REGISTERS
;====================================
;
SAVY:	.WORD	0	;Y REG
SAVHLP:	.WORD	0	;HL' REG
SAVDEP:	.WORD	0	;DE' REG
SAVBCP:	.WORD	0	;BC' REG
SAVAFP:	.WORD	0	;PSW' REG
SAVSP:	.WORD	0	;SP
SAVX:	.WORD	0	;X REG
SAVHL:	.WORD	0	;HL REG
SAVDE:	.WORD	0	;DE REG
SAVBC:	.WORD	0	;BC REG
SAVPSW:	.WORD	0	;AF REG
SAVRST:	.WORD	0	;LOC OF RST
WSTAK:	.BLKB	20H	;ROOM FOR STACK
STACK:	.BLKB	20H	;LOCAL STACK
;
.END  INIT
